<?php

/**
 * Permite manejar excepciones generadas dentro de la aplicación.
 * 
 * Si las mismas no son capturadas por el metodo que las genera, seran capturadas 
 * y manejadas al final por el controlador frontal. 
 * Se recomienda establecer los controles para manejo de excepciones desde los 
 * mismos metodos que las generen
 * 
 * @author Robert babilonia <bobbabilon2@gmail.com>
 * 
 * 
 */
class CommanderException extends Exception {

    /**
     * Codigo de error de la Excepcion
     *
     * @var string
     */
    public static $_view = NULL;

    /**
     * Constructor de la clase;
     *
     * @param string $message mensaje
     * @param string $code vista que se mostrara
     * @param Exception $previous Excepcion previamente capturada
     * 
     */
    public function __construct($message, $code = '404', $previous = NULL) {
        CommanderException::$_view = $code;
        parent::__construct($message, $code, $previous);
    }

    /**
     * Hace que comander maneje una excepcion previamente capturada
     * @param Exception $e
     * @param string $view
     */
    public static function catch_exception(Exception $e, $view = '404') {


        $obj = new CommanderException($e->getMessage(), $view);
        $obj->get_exception();
    }

    /**
     * Captura los errores en tiempo de ejecucion y los transforma en excepciones de commander
     * @param int $errno
     * @param string $errstr
     * @param string $errfile
     * @param int $errline
     * @throws ErrorException
     */
    public static function frame_error_handler($errno, $errstr, $errfile = '', $errline = 0) {

        try {

            throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
        } catch (Exception $excepcion) {

            self::manage_exceptions($excepcion);
        }
    }

    /**
     * Capturador definido para las excepciones no atrapadas
     * @param Exception $excepcion
     */
    public static function frame_exception_handler($excepcion) {

        self::manage_exceptions($excepcion);
    }

    /**
     * Capturar los errores fatales en tiempo de ejecucion, para dar un manejo 
     * mas limpio desde del frame
     */
    public static function fatal_error_shutdown_handler() {

        $last_error = error_get_last();
        if ($last_error['type'] === E_ERROR || $last_error['type'] === E_PARSE) {


            CommanderException::frame_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
        }
    }

    /**
     * Manipula internamente las excepciones recibidas para enviar una vista de error
     * @param Exception $excepcion
     */
    private static function manage_exceptions($excepcion) {

        //se obtiene el mensaje de error de la excepcion
        $vista_file = VIEWS_PATH . '__errors' . DIRECTORY_SEPARATOR . CommanderException::$_view . '.php';
        $error_mensaje = CommanderException::get_render_message($excepcion);


        if (is_file($vista_file)) {

            require_once $vista_file;
        } else {

            require_once VIEWS_PATH . '__errors' . DIRECTORY_SEPARATOR . '404.php';
        }
    }

    /**
     * Obtiene la informacion de la excepcion y envia la respuesta a la vista de 
     * error indicada en el atributo _view
     * @author Robert babilonia <bobbabilon2@gmail.com>
     * 
     */
    public function get_exception() {


        //se registra en log el error
        CommanderLogger::jump_log();
        CommanderLogger::fatal_log($this->getMessage());
        CommanderLogger::fatal_log($this->getTraceAsString());


        self::manage_exceptions($this);
    }

    /**
     * Obtiene el mensaje de una excepcion con algun nivel de formato,
     * si la opcion de traceroute esta habilitada se muestra, de lo contrario 
     * solo se muestra el mensaje generado
     * @param Exception $e Excepcion recibida
     * 
     * 
     */
    private static function get_render_message(Exception $e) {



        if (CommanderApp::get_config('TRACE_ROUTE')) {

            $error_mensaje = $e->getMessage();
            $error_array = $e->getTrace();

            $error_mensaje.="<br/>";

            if (is_array($error_array)) {

                foreach ($error_array as $registro => $traza) {

                    $error_mensaje.="<br/>$registro:  ";
                    $cont = 0;
                    foreach ($traza as $indice => $valor) {


                        if ($cont++ > 0) {

                            $error_mensaje.=", ";
                        }

                        if (is_array($valor)) {


                            $cadena = "";
                            $cont2 = 0;
                            foreach ($valor as $something) {

                                if (is_object($something)) {

                                    $something = get_class($something);
                                } elseif (is_array($something)) {
                                    $tela = '';
                                    $cont3 = 0;
                                    foreach ($something as $thing) {


                                        if ($cont3++ > 0) {

                                            $tela.=", ";
                                        }

                                        if (is_string($thing)) {
                                            $tela.="$thing ";
                                        }
                                    }
                                    $something = $tela;
                                }


                                if ($cont2++ > 0) {

                                    $cadena.=", ";
                                }

                                $cadena.="$something ";
                            }

                            $valor = $cadena;
                        }




                        $error_mensaje.="$indice: $valor ";
                    }

                    $error_mensaje.="<br/>";
                }
            }
        } else {


            $error_mensaje = ERROR_404;
        }

        return $error_mensaje;
    }

}